//------------------------------------------------------------------------------
// <copyright file="MainWindowViewModel.cs" company="Damian Antonowicz">
//       copyright © 2010 Damian Antonowicz
// </copyright>
// <author>Damian Antonowicz</author>
// <email>poczta@damianantonowicz.pl</email>
//------------------------------------------------------------------------------

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using DotBeer.Business.Entities;
using DotBeer.Data.Properties;
using DAnton.Utilities.Extensions;
using DotBeer.Business.Components;
using DotBeer.UI.WPFClient.Commands;
using System.Diagnostics;
using System.Windows.Input;
using System.Windows;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using DAnton.Utilities.Extensions;

namespace DotBeer.UI.WPFClient.ViewModels
{
    public class MainWindowViewModel : HeroViewModelBase
    {
        #region private members

        DelegateCommand editCommand;
        DelegateCommand printCommand;
        DelegateCommand aboutCommand;
        DelegateCommand optionsCommand;
        DelegateCommand refreshCommand;
        DelegateCommand hideOrShowMenuCommand;
        DelegateCommand loadHeroBySearchHeroNameCommand;
        DelegateCommand<string> changeSideCommand;
        DelegateCommand completeChangeSideCommand;
        DelegateCommand addNewBuildCommand;
         
        Window optionsWindow, aboutWindow, printWindow, editWindow;
        Func<object> editWindowLoadViewModelByHeroNameAuthorName,
                     editWindowLoadViewModelByHeroName,
                     optionsWindowLoadViewModelMethod;

        ObservableCollection<ItemHero> filteredCurrentItems = new ObservableCollection<ItemHero>();
        Side selectedSide;
        PropertyState selectedSideState = PropertyState.None;
        string searchHeroName;

        #endregion

        #region properties

        public string SearchHeroName
        {
            //get;
            set { this.searchHeroName = value; }
        }

        public bool MenuExpanded
        {
            get { return WindowMainSettings.Default.ManuGridExpanded; }
        }

        public double InitialMenuXPosition
        {
            get
            {
                if (WindowMainSettings.Default.ManuGridExpanded)
                    return -214;
                else
                    return 0;
            }
        }

        public Side SelectedSide
        {
            get { return this.selectedSide; }
            set
            {
                this.SelectedSideState = PropertyState.Changing;
                this.selectedSide = value;
                this.SelectedSideState = PropertyState.Changed;
            }
        }

        public PropertyState SelectedSideState
        {
            get { return this.selectedSideState; }
            private set
            {
                this.selectedSideState = value;
                this.OnPropertyChanged("SelectedSideState");
            }
        }

        public ObservableCollection<ItemHero> FilteredCurrentItems
        {
            get { return this.filteredCurrentItems; }
        }

        public bool ShowAll
        {
            get { return DisplayOptionsSettings.Default.ShowAll; }
            set
            {
                DisplayOptionsSettings.Default.ShowAll = value;
                DisplayOptionsSettings.Default.Save();

                GetFilteredCurrentItems();
                this.OnPropertyChanged("ShowAll");
            }
        }

        public bool ShowCore
        {
            get { return DisplayOptionsSettings.Default.ShowCore; }
            set
            {
                DisplayOptionsSettings.Default.ShowCore = value;
                DisplayOptionsSettings.Default.Save();

                GetFilteredCurrentItems();
                this.OnPropertyChanged("ShowCore");
            }
        }

        public bool ShowAfterwards
        {
            get { return DisplayOptionsSettings.Default.ShowAfterwards; }
            set
            {
                DisplayOptionsSettings.Default.ShowAfterwards = value;
                DisplayOptionsSettings.Default.Save();

                GetFilteredCurrentItems();
                this.OnPropertyChanged("ShowAfterwards");
            }
        }

        public bool ShowOptional
        {
            get { return DisplayOptionsSettings.Default.ShowOptional; }
            set
            {
                DisplayOptionsSettings.Default.ShowOptional = value;
                DisplayOptionsSettings.Default.Save();

                GetFilteredCurrentItems();
                this.OnPropertyChanged("ShowOptional");
            }
        }

        public bool ShowCustom
        {
            get { return DisplayOptionsSettings.Default.ShowCustom; }
            set
            {
                DisplayOptionsSettings.Default.ShowCustom = value;
                DisplayOptionsSettings.Default.Save();

                GetFilteredCurrentItems();
                this.OnPropertyChanged("ShowCustom");
            }
        }

        public string CustomTypes
        {
            get { return DisplayOptionsSettings.Default.CustomTypes; }
            set
            {
                DisplayOptionsSettings.Default.CustomTypes = value;
                DisplayOptionsSettings.Default.Save();

                GetFilteredCurrentItems();
                this.OnPropertyChanged("CustomTypes");
            }
        }

        #endregion

        #region commands

        public DelegateCommand AddNewBuildCommand
        {
            get
            {
                if (this.addNewBuildCommand == null)
                    this.addNewBuildCommand = new DelegateCommand(this.AddNewBuild, this.CanShowHeroAssocatiedWindow);

                return this.addNewBuildCommand;
            }
        }

        public DelegateCommand LoadHeroBySearchHeroNameCommand
        {
            get
            {
                if (this.loadHeroBySearchHeroNameCommand == null)
                    this.loadHeroBySearchHeroNameCommand = new DelegateCommand(this.LoadHeroBySearchHeroName);

                return this.loadHeroBySearchHeroNameCommand;
            }
        }

        public DelegateCommand<string> ChangeSideCommand
        {
            get
            {
                if (this.changeSideCommand == null)
                    this.changeSideCommand = new DelegateCommand<string>(this.ChangeSide);

                return this.changeSideCommand;
            }
        }

        public DelegateCommand CompleteChangeSideCommand
        {
            get
            {
                if (this.completeChangeSideCommand == null)
                    this.completeChangeSideCommand = new DelegateCommand(this.CompleteChangeSide);

                return this.completeChangeSideCommand;
            }
        }

        public DelegateCommand HideOrShowMenuCommand
        {
            get
            {
                if (this.hideOrShowMenuCommand == null)
                    this.hideOrShowMenuCommand = new DelegateCommand(this.HideOrShowMenu);

                return this.hideOrShowMenuCommand;
            }
        }

        public DelegateCommand ShowEditWindowCommand
        {
            get
            {
                if (this.editCommand == null)
                    this.editCommand = new DelegateCommand(this.ShowEditWindow, this.CanShowHeroAssocatiedWindow);

                return this.editCommand;
            }
        }

        public DelegateCommand ShowPrintWindowCommand
        {
            get
            {
                if (this.printCommand == null)
                    this.printCommand = new DelegateCommand(this.ShowPrintWindow, this.CanShowHeroAssocatiedWindow);

                return this.printCommand;
            }
        }

        public DelegateCommand ShowAboutWindowCommand
        {
            get
            {
                if (this.aboutCommand == null)
                    this.aboutCommand = new DelegateCommand(this.ShowAboutWindow);

                return this.aboutCommand;
            }
        }

        public DelegateCommand ShowOptionsWindowCommand
        {
            get
            {
                if (this.optionsCommand == null)
                    this.optionsCommand = new DelegateCommand(this.ShowOptionsWindow);

                return this.optionsCommand;
            }
        }

        public DelegateCommand RefreshCommand
        {
            get
            {
                if (this.refreshCommand == null)
                    this.refreshCommand = new DelegateCommand(this.RefreshBuild, this.CanRefreshBuild);

                return this.refreshCommand;
            }
        }

        #endregion

        #region constructors

        public MainWindowViewModel()
        {
            this.PropertyChanged += new PropertyChangedEventHandler(MainViewModel_PropertyChanged);
            this.PropertyChanging += new EventHandler<PropertyChangingEventArgs>(MainViewModel_PropertyChanging);
            DisplayOptionsSettings.Default.PropertyChanged += new PropertyChangedEventHandler(DisplayOptionsSettings_PropertyChanged);
        }

        #endregion

        #region private methods

        private void LoadHeroBySearchHeroName()
        {
            this.LoadHeroByHeroName(this.searchHeroName);
        }

        private void ChangeSide(string side)
        {
            this.SelectedSide = (Side)Enum.Parse(typeof(Side), side);
        }

        private void CompleteChangeSide()
        {
            this.OnPropertyChanged("SelectedSide");
        }

        private void HideOrShowMenu()
        {
            WindowMainSettings.Default.ManuGridExpanded = !WindowMainSettings.Default.ManuGridExpanded;
            WindowMainSettings.Default.Save();
            this.OnPropertyChanged("MenuExpanded");
        }

        private void AddNewBuild()
        {
            if (this.CanShowHeroAssocatiedWindow())
            {
                if (this.editWindowLoadViewModelByHeroName == null)
                {
                    this.editWindowLoadViewModelByHeroName = () =>
                        {
                            return new EditWindowViewModel(this.hero.Name);
                        };
                }

                this.OpenOrFocusWindow(ref this.editWindow, 
                                       null, 
                                       this.editWindowLoadViewModelByHeroName, 
                                       typeof(WindowEdit), 
                                       false);
            }
        }

        private void ShowEditWindow()
        {
            if (this.CanShowHeroAssocatiedWindow())
            {
                if (this.editWindowLoadViewModelByHeroNameAuthorName == null)
                {
                    this.editWindowLoadViewModelByHeroNameAuthorName = () =>
                    {
                        return new EditWindowViewModel(this.hero.Name, this.hero.Author);
                    };
                }

               this.OpenOrFocusWindow(ref this.editWindow, 
                                      null, 
                                      this.editWindowLoadViewModelByHeroNameAuthorName, 
                                      typeof(WindowEdit), 
                                      false);
            }
        }

        private void ShowPrintWindow()
        {
            if (this.CanShowHeroAssocatiedWindow())
                this.OpenOrFocusWindow(ref this.printWindow, 
                                       new object[] { this.Hero }, 
                                       null, 
                                       typeof(WindowPrintingOptions), 
                                       true);
        }

        private void ShowAboutWindow()
        {
            this.OpenOrFocusWindow(ref this.aboutWindow, 
                                   null, 
                                   null, 
                                   typeof(WindowAbout), 
                                   true);
        }

        private void ShowOptionsWindow()
        {
            if (this.optionsWindowLoadViewModelMethod == null)
            {
                this.optionsWindowLoadViewModelMethod = () =>
                    {
                        return new OptionsWindowViewModel();
                    };
            }

            this.OpenOrFocusWindow(ref this.optionsWindow, 
                                   null, 
                                   this.optionsWindowLoadViewModelMethod, 
                                   typeof(WindowOptions), 
                                   false);
        }

        private void RefreshBuild()
        {
            this.LoadHero(this.Hero.Name, this.Hero.Author);
        }

        private bool CanRefreshBuild()
        {
            return this.Hero != null;
        }

        private void GetFilteredCurrentItems()
        {
            this.filteredCurrentItems.Clear();
            this.filteredCurrentItems.AddRange(HeroComponent.GetFilteredCurrentItems(hero));
        }

        private void MainViewModel_PropertyChanging(object sender, PropertyChangingEventArgs e)
        {
            if (e.PropertyName == "Hero")
            {
                this.filteredCurrentItems.Clear();

                if (hero != null)
                    hero.PropertyChanged -= hero_PropertyChanged;
            }
        }

        private void MainViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Hero" && hero != null)
                hero.PropertyChanged += new PropertyChangedEventHandler(hero_PropertyChanged);
        }

        private void hero_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "CurrentItems")
                GetFilteredCurrentItems();
        }

        private bool CanShowHeroAssocatiedWindow()
        {
            return !(hero == null);
        }

        private void DisplayOptionsSettings_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            this.OnPropertyChanged(e.PropertyName);
        }

        private void OpenOrFocusWindow(ref Window window, 
                                       object[] parameters, 
                                       Func<object> viewModelLoadMethod, 
                                       Type windowType, 
                                       bool isDialogWindow)
        {
            if (window == null || !window.IsLoaded)
            {
                List<Type> types = new List<Type>();

                if (parameters != null)
                    types.AddRange(parameters.Select(o => o.GetType()));

                ConstructorInfo ci = windowType.GetConstructor(types.ToArray());
                window = ci.Invoke(parameters) as Window;

                if (viewModelLoadMethod != null)
                    window.DataContext = viewModelLoadMethod();
            }

            if (isDialogWindow)
                window.ShowDialog();
            else
            {
                if (window.IsLoaded)
                    window.Focus();
                else
                    window.Show();
            }
        }

        #endregion
    }
}
